<script lang="ts">
    import Icon from "../Common/Icons/Icon.svelte";
    import { useFormItemContext } from "../FormItem/FormItem.svelte";
    import { Input } from "../Input";
    import { useClassList } from "../utils/useClassList";
    import type { SpinnerProps } from "./Spinner";

    let { min = 0, value = $bindable(Math.max(0, min ?? 0)), ...props }: SpinnerProps = $props();
    const ctx = useFormItemContext();
    const step = props.step || 1;

    const classList = $derived(
        useClassList(props, "cm-spinner", {
            [`cm-spinner-${props.size}`]: props.size,
            "cm-spinner-disabled": props.disabled,
        })
    );

    const _onInput = (val: string, e: any) => {
        val = val.replace(/[^0-9\.]/g, "");
        e.target.value = val;
    };

    const _onKeyDown = (e: any) => {
        if (e.keyCode === 38) {
            plus();
        }
        if (e.keyCode === 40) {
            sub();
        }
    };

    const _onChange = (v: number) => {
        let val = v;
        if (props.max !== undefined) {
            val = Math.min(val, props.max);
        }
        if (min !== undefined) {
            val = Math.max(val, min);
        }

        value = val;

        props.onchange?.(val);
        ctx?.onFieldChange?.();
    };

    /**
     * 增加
     * @memberof Spinner
     */
    const plus = () => {
        if (props.disabled) {
            return;
        }
        let v = add(value, step);
        if (props.loop && props.max !== undefined && min !== undefined && v > props.max) {
            const off = v - props.max;
            v = min + off - 1;
        }

        if (props.max !== undefined) {
            v = Math.min(props.max, v);
        }

        value = v;
        props.onchange?.(v);
        props.onplus?.(v, step);
        ctx?.onFieldChange?.();
    };

    /**
     * 减少
     * @memberof Spinner
     */
    const sub = () => {
        if (props.disabled) {
            return;
        }
        let v = add(value, -step);
        if (props.loop && props.max !== undefined && min !== undefined && v < min) {
            const off = v - min;
            v = props.max + off + 1;
        }
        if (min !== undefined) {
            v = Math.max(min, v);
        }

        value = v;
        props.onchange?.(v);
        props.onsub?.(v, step);
        ctx?.onFieldChange?.();
    };

    /**
     * 解决数字浮点型双精度问题
     * @param {[type]} num1 [description]
     * @param {[type]} num2 [description]
     */
    function add(num1: number, num2: number): number {
        let r1;
        let r2;
        try {
            r1 = num1.toString().split(".")[1].length;
        } catch (e) {
            r1 = 0;
        }
        try {
            r2 = num2.toString().split(".")[1].length;
        } catch (e) {
            r2 = 0;
        }
        const m = Math.pow(10, Math.max(r1, r2));
        return (num1 * m + num2 * m) / m;
    }
</script>

<Input class={classList} style={props.style} size={props.size} placeholder={props.placeholder} disabled={props.disabled} oninput={_onInput} bind:value onchange={_onChange} onkeydown={_onKeyDown}>
    {#snippet append()}
        <!-- svelte-ignore a11y_no_static_element_interactions -->
        <!-- svelte-ignore a11y_click_events_have_key_events -->
        <span class="cm-spinner-plus" onclick={plus}>
            <Icon icon="chevronUp" />
        </span>
        <!-- svelte-ignore a11y_no_static_element_interactions -->
        <!-- svelte-ignore a11y_click_events_have_key_events -->
        <span class="cm-spinner-subs" onclick={sub}>
            <Icon icon="chevronDown" />
        </span>
    {/snippet}
</Input>
